#include <QQueue>

#include "hbot_class.h"
#include "hbot.h"
#include "operationthread.h"
#include "sdefs.h"

/* OperationQueue and OperationThread classes developed by help/support of 'LadyGaGa' and 'FlyLo' off of the codelain forums. Thanks for the help. */

OperationQueue::OperationQueue()
{

}

OperationQueue::~OperationQueue()
{

}

void OperationQueue::Enqueue(CBaseOperation *opClass, void (*functPointer)(CBaseOperation *, QSqlDatabase *))
{
	m_QueueMutex.lock();
	m_OperationQueue.enqueue(PairedOperation(opClass, functPointer));
	m_QueueNotEmpty.wakeOne();
	m_QueueMutex.unlock();
}

PairedOperation OperationQueue::Dequeue()
{
	m_QueueMutex.lock();

	if (m_OperationQueue.isEmpty())
	{
		m_QueueNotEmpty.wait(&m_QueueMutex);
	}

	PairedOperation op = m_OperationQueue.dequeue();
	m_QueueMutex.unlock();

	return op;
}

OperationThread::OperationThread(const QString &connectionIdentifier, OperationQueue *queue, QThread::Priority priority, QObject *parent): QThread()
{
	m_ConnectionIdentifier = connectionIdentifier;
	m_Queue = queue;
	
	connect(this, SIGNAL(ErrorChanged(const QString &error, const QString &databaseType, const QString &connectionIdentifier)), g_HBotClass.GetDatabase(), SLOT(SetError(const QString &error, const QString &databaseType, const QString &connectionIdentifier)));

	if (g_HBotClass.GetDatabaseType() == 0)
	{
		m_Database = QSqlDatabase::addDatabase("QSQLITE", "OperationThread[" + m_ConnectionIdentifier + "]");
		m_Database.setDatabaseName(g_HBotClass.GetDatabase()->GetFileName());

		if (!m_Database.open())
		{
			emit ErrorChanged("Error: Unable to establish a database connection to file [" + g_HBotClass.GetDatabase()->GetFileName() + "]. Please be sure that the path to the file exists.", g_HBotClass.GetDatabaseType() == 0 ? "SQLite" : "MySQL", m_ConnectionIdentifier);
			return;
		}

		g_HBot.PrintConsole(PRINT_CONSOLE_GROUP_DATABASE, "Successfully established a connection to file [" + g_HBotClass.GetDatabase()->GetFileName() + "].", "SQLite - OT(" + m_ConnectionIdentifier + ")");
	}
	else if (g_HBotClass.GetDatabaseType() == 1)
	{
		/* ESTABLISH MYSQL CONNECTION */
	}
	else
	{
		emit ErrorChanged("Error: A SQLite or MySQL database was not successfully created.", g_HBotClass.GetDatabaseType() == 0 ? "SQLite" : "MySQL", m_ConnectionIdentifier);
		return;
	}
	
	start(priority);
}

OperationThread::~OperationThread()
{
	g_HBot.PrintConsole(PRINT_CONSOLE_GROUP_DATABASE, "Closing SQLite3 database connection to file [" + g_HBotClass.GetDatabase()->GetFileName() + "]", "SQLite - OT(" + m_ConnectionIdentifier + ")");

	m_Database.close();
	QSqlDatabase::removeDatabase("OperationThread[" + m_ConnectionIdentifier + "]");
}

void OperationThread::run()
{
	forever
	{
		PairedOperation op = m_Queue->Dequeue();

		void (*operation)(CBaseOperation *, QSqlDatabase *) = op.second;
		operation(op.first, &m_Database);
	}
}
